package com.example.codegenerator.Service;

import com.example.codegenerator.Constant.PathConstant;
import com.example.codegenerator.Constant.TemplateConstant;
import com.example.codegenerator.Utils.FreemarkerUtils;
import com.example.codegenerator.po.Column;
import com.example.codegenerator.Constant.TypeConstant;
import com.example.codegenerator.po.Entity;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.sql.*;
import java.util.*;

@Service
public class MainService {
    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    FreemarkerUtils utils;

    /**
     * 一键代码生成
     * @param dbName 数据库名
     * @param tableName 数据表名
     */
    public void generator(String dbName, String tableName){
        Entity entity = getDataModel(dbName, tableName);
        generateEntity(entity);
        generateMapper(entity);
        generatorService(entity);
        generatorServiceImpl(entity);
        generatorController(entity);
    }

    /**
     * 生成实体类
     */
    public void generateEntity(Entity entity){
        try {
            utils.generatorEntity(entity, TemplateConstant.EntityTemplate);
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }
        System.out.println("生成文件："+entity.entityName);
    }

    /**
     * 生成Mapper类
     * mybatis-plus-mapper
     */
    public void generateMapper(Entity entity){
        try {
            utils.generatorMapper(entity, TemplateConstant.mapperTemplate);
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }
        System.out.println("生成文件："+entity.entityName+"Mapper");
    }

    /**
     * 生成Service接口
     */
    public void generatorService(Entity entity){
        try {
            utils.generatorService(entity, TemplateConstant.serviceTemplate);
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }
        System.out.println("生成文件："+entity.entityName+"Service");
    }

    /**
     * 生成ServiceImpl类
     */
    public void generatorServiceImpl(Entity entity){
        try {
            utils.generatorServiceImpl(entity, TemplateConstant.serviceImplTemplate);
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }
        System.out.println("生成文件："+entity.entityName+"ServiceImpl");
    }

    /**
     * 生成Controller类
     */
    public void generatorController(Entity entity){
        try {
            utils.generatorController(entity, TemplateConstant.controllerTemplate);
        } catch (IOException | TemplateException e) {
            throw new RuntimeException(e);
        }
        System.out.println("生成文件："+entity.entityName+"Controller");
    }

    /**
     * 获取数据模型
     * 用于代码生成
     */
    public Entity getDataModel(String dbName, String tableName){
        List<Column> columns = null;
        try {
            columns = getColumns(dbName, tableName);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        Entity entity = Entity.builder()
                .entityName(processTableName(tableName))
                .tableName(tableName)
                .packageName(PathConstant.packageName)
                .columns(columns)
                .build();
        return entity;
    }

    /**
     * 获取对应表的列数据
     */
    private List<Column> getColumns(String dbName, String tableName) throws SQLException {
        // 获取数据表元数据
        Connection connection = getConnection();
        DatabaseMetaData metaData = getMetaData(connection);
        ResultSet columns = metaData.getColumns(dbName, dbName, tableName, null);

        // 获取列信息
        List<Column> list = new ArrayList<>();

        while (columns.next()) {
            String columnName = columns.getString("COLUMN_NAME"); // 列名
            int columnType = columns.getInt("DATA_TYPE");// 数据类型
            String columnTypeName = columns.getString("TYPE_NAME"); // 数据类型名
            int columnSize = columns.getInt("COLUMN_SIZE"); // 列大小
            int decimalDigits = columns.getInt("DECIMAL_DIGITS"); // 小数位数
            boolean isNullable = columns.getBoolean("NULLABLE"); // 是否允许空

            // 构造列对象
            Column column = Column.builder()
                    .columnName(CamelCaseConversion(columnName))
                    .columnType(columnType)
                    .columnTypeName(columnTypeName)
                    .name(TypeConstant.getType(columnTypeName))
                    .columnSize(columnSize)
                    .decimalDigits(decimalDigits)
                    .isNullable(isNullable)
                    .build();

            // 添加仅列表
            list.add(column);
        }
        connection.close();
        return list;

    }


    /**
     * 驼峰转换
     */
    private String CamelCaseConversion(String name){
        StringBuilder s = new StringBuilder(name);
        for(int i = 0;i < s.length();i++){
            if(s.charAt(i) == '_'){
                s.deleteCharAt(i);
                s.replace(i,i+1, String.valueOf(Character.toUpperCase(s.charAt(i))));
            }
        }
        return s.toString();
    }

    /**
     * 获取当前数据库连接
     */
    private Connection getConnection(){
        Connection connection = null;
        try {
            connection = jdbcTemplate.getDataSource().getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return connection;
    }

    /**
     * 获取当前数据库连接
     */
    private DatabaseMetaData getMetaData(Connection connection){
        DatabaseMetaData metaData = null;
        try {
            metaData = connection.getMetaData();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return metaData;
    }

    /**
     * 将首字母大写
     */
    private String processTableName(String tableName){
        StringBuilder s = new StringBuilder(tableName);
        s.replace(0,1, String.valueOf(Character.toUpperCase(s.charAt(0))));
        return s.toString();
    }

}
